package cn.itsource.hashmap;

import java.util.HashMap;

/**
 *	Map：
 *		1. 概念：Map:就是用来装键值对集合的容器
 *		2. 作用：
 *				解决了需要成对出现的这种关系结构
	 *				键(key)   ： 	质就是一个数据
					值(value)   ： 	本质也是一个数据
					键值对： 就是一对（和两个是有区别的），一对一般是有某种关系
 *				例如：
 *					1、例如QQ的账号+密码：想象场景-需要使用一个集合搜集各位100人的QQ号码和密码；
					2、银行账户和密码
					3、游戏账号和密码
					4、搜集各位的姓名+女朋友的姓名 （情侣关系）
					5、坐标（x,y）
					6、....
 *		3. 
 *			Map的继承体系
			Map   接口
			  |--   HashMap   ：基于hashCode(),底层是Entry键值对的数组，数组中装装的是键值对，会根据添加的key的hashCode值 模 当前数组的length（默认是16），
			  		而得到数组的下标，进而保存键值对。如果key模length后，得到的下标是相等的，就会发生hash碰撞（哈希冲突），这时候再继续判断key的equals方法，
			  		如果equals判断为true，就会将原来的键值对覆盖，如果是false，就会在该下标处的原来键值对后面形成  链表，如果链表长度达到8个，就形成		红黑树。
			  		当删除键值对后剩余的数量小于等于6的时候，就重新将红黑树，退化为链表。（jdk1.8）put添加/remove删除
			  		
			  		key判断键是否重复和HashSet判断重复一样:1. hashCode  2.equals()
			  |		HashMap底层是Entry（键值对）的数组，并且维护了链表和红黑树
			  		
			  |--   HashTable   ： 就是一个线程安全的HashMap
			  			|--	Properties：特殊的HashTable（是HashTable子类），只不过key-value都是String类型，一般用来做
					  		配置文件：（解决硬编码问题的文件）
					  			1. .xml
					  			2. .properties
					  			3. .ini/.init
					  			4. .yml (SprintBoot)
					  			
			  |--   ConcurrentHashMap   ： 就是一个线程安全且效率更高的的HashTable，理论上是HashTable的16倍
			  |--   LinkedHashMap： 就是一个内部维护了一个链表的HashMap，可以保证存入和取出顺序
			  
 *				
			  |--   TreeMap    ： 判断key重复的规则和TreeSet一样
					TreeMap中的键（key）要么是具有自然排序能力(需要key实现Comparable接口，重写CompareTo方法)；
					或者TreeMap中提供一个比较器Comparetor实现类对象
					如果key是自然或者定制排序，返回值是0表示，key是重复的，如果是正数，则按照key的升序排序，否则是降序
					
		4. HashMap底层原理参见source文件夹中的图片			
 */
public class HashMapTest {

	public static void main(String[] args) {
		/*
		 * 构造方法：
		 * 		1. HashMap()构造一个空的 HashMap ，默认初始容量（16）和默认负载系数（0.75）。  
				2. HashMap(int initialCapacity) 构造一个空的 HashMap具有指定的初始容量和默认负载因子（0.75）。  
					避免哈希碰撞
				3. HashMap(int initialCapacity, float loadFactor) 构造一个空的 HashMap具有指定的初始容量和负载因子。  
				4. HashMap(Map m) 构造一个新的 HashMap与指定的相同的映射 Map 。  
		 */
		HashMap hashMap = new HashMap();
		
		//1.V put(K key, V value)如果当前key，没有，则是添加操作，如果key是存在的则进行equals判断，如果equals相等，则是覆盖操作，如果equals不相等，value追加到末尾则会形成链表或者红黑树
		hashMap.put(1, "1");
		hashMap.put(1, "1");
//		System.out.println(hashMap);
		hashMap.put(1, "2");
		hashMap.put(2, "2");
		hashMap.put(3, "3");
//		System.out.println(hashMap);
		hashMap.clear();//清除所有键值对元素
		//====================key是自定义类型=====================
		Student stu1 = new Student("张X民",16);
		Student stu2 = new Student("张X民",17);
		Student stu3 = new Student("张X民有点小",17);
		Student stu4 = new Student("张X民有点小",19);
		Student stu5 = new Student("张X民",16);
		
		System.out.println(stu1.hashCode());
		System.out.println(stu5.hashCode());
		System.out.println(stu1.equals(stu5));
		
		hashMap.put(stu1,"确实很小");//key是stu1和stu5的hashCode和equals比较都是相等的，执行value覆盖操作
		hashMap.put(stu2,"真的很小很小");
		hashMap.put(stu3,"确实非常非常小");
		hashMap.put(stu4,"用放大镜才能看得到");
		hashMap.put(stu5,"用天文望远镜才能看得到");//key是stu1和stu5的hashCode和equals比较都是相等的，执行value覆盖操作
		System.out.println(hashMap);
		hashMap.put(stu1,"完了，消失了！！！！");
		System.out.println(hashMap);
		//2.void putAll(Map m) 将传入的Map作为参数，创建一个新的HashMap对象
//		HashMap hashMap2 = new HashMap();
//		System.out.println(hashMap2);
//		hashMap2.putAll(hashMap);
//		System.out.println(hashMap2);
		
		//3.V get(Object key)根据key去获取value值,如果key不存在，则返回null
		Object object = hashMap.get(stu1);
		System.out.println(object);
		
		//4.V remove(Object key)根据key删除当前map对象中的这一对键值对  
//		Object remove = hashMap.remove(stu1);
//		System.out.println("删除的值："+remove);
//		System.out.println("删除后："+hashMap);
		
		//5.boolean remove(Object key, Object value)只有key和value都存在的时候，才能删除
//		boolean remove = hashMap.remove(stu1,"完了，消失了！！！！");
//		System.out.println("删除是否成功："+ remove);
//		System.out.println("删除后："+hashMap);
		
		//6.V replace(K key, V value)根据key替换为新的value的值
//		Object replace = hashMap.replace(stu1,"可能够不到");
//		System.out.println("替换了："+ replace);
//		System.out.println("替换后："+hashMap);
		
		//7.boolean replace(K key, V oldValue, V newValue)  只有当key和value都存在的情况下，才能替换为新的  newValue值
//		boolean replace = hashMap.replace(stu1,"完了，消失了！！！！","太小了");
//		System.out.println("替换是否成功："+ replace);
//		System.out.println("替换后："+hashMap);
		
		//8.boolean containsKey(Object key)判断当前map集合对象中是否包含这个key
		boolean containsKey = hashMap.containsKey(new Student("苍苍",40));
		System.out.println(containsKey);
		
		//9.boolean containsValue(Object value)判断当前map集合对象中是否包含这个value，包含则返回 true 。  
		boolean containsValue = hashMap.containsValue("完了，消失了！！！！");
		System.out.println(containsValue);
		
		//10.void clear()清除所有的键值对对象
		
		//11.boolean isEmpty()判段当前map对象是否是空集合 。  
		System.out.println(hashMap.isEmpty());
		
		//12.int size()返回此地图中键值映射的数量。  
		System.out.println(hashMap.size());
		
	}

}
class Student{
	private String name;
	private int age;
	
	public Student() {
		super();
	}
	
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "[" + name + ", " + age + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	
}
